#pragma once

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#include <functional>

int name_cnt = 1;

namespace My_Thread
{
    class Thread
    {
        using fun_t = std::function<void()>;

    private:
        // 启动线程前设置分离
        void ChangeID()
        {
            _isdetach = true;
        }

        static void *routine(void *args)
        {
            Thread *self = static_cast<Thread *>(args);

            self->_fun();

            // 现在线程处在运行时，如果在运行前已经将_isdetach设置为true，则调用Detach.
            if (self->_isdetach)
                self->Detach();

            // Start之后更改线程状态
            if (!(self->_isrunning))
                self->ChangeIR();

            return nullptr;
        }

        // 改变线程的运行状态
        void ChangeIR()
        {
            _isrunning = true;
        }

    public:
        Thread(fun_t fun) : _tid(0), _isrunning(false), _isdetach(false), _fun(fun)
        {
            _name = "thread-" + std::to_string(name_cnt++);
        }

        // 这样子在类内写routine函数，导致参数不符合，因为有this指针
        //  void *routine(void* args)
        //  {

        // }

        bool Detach()
        {
            if (_isdetach)
            {
                return false;
            }

            if (_isrunning)
            {
                int n = pthread_detach(_tid);
                if (n != 0)
                {
                    std::cerr << "Detath fail: " << strerror(n) << std::endl;
                    return false;
                }
                else
                {
                    std::cout << "Detach success!" << std::endl;
                    return true;
                }
            }
            ChangeID();

            return true;
        }

        bool Start()
        {
            if(_isrunning)
            {
                std::cout<<"The thread is running!"<<std::endl;
            }
            // 传递this指针给routine函数，这样可以调用成员变量_fun
            int n = pthread_create(&_tid, nullptr, routine, this);
            if (n != 0)
            {
                std::cerr << "Start fail: " << strerror(n) << std::endl;
                return false;
            }
            else
            {
                std::cout << "Start success!" << std::endl;
            }

            // 将判断 isdetach 和 isrunning放在routine函数之中健壮性更好
            //  // 现在线程处在运行时，如果在运行前已经将_isdetach设置为true，则调用Detach.
            //  if (_isdetach)
            //      Decath();

            // // Start之后更改线程状态
            // if (!_isrunning)
            //     ChangeIR();

            return true;
        }

        bool Stop()
        {
            int n = pthread_cancel(_tid);
            if (n != 0)
            {
                std::cerr << "Stop fail: " << strerror(n) << std::endl;
                return false;
            }
            else
            {
                std::cout << "Stop success!" << std::endl;
                _isrunning = false;
                return true;
            }

            return true;
        }

        bool Join()
        {
            if (!_isdetach)
            {
                int n = pthread_join(_tid, &_ret);
                if (n != 0)
                {
                    std::cerr << "Join fail: " << strerror(n) << std::endl;
                    return false;
                }
                else
                {
                    std::cout << "Join success!" << std::endl;
                    return true;
                }

                return true;
            }
            else
            {
                return false;
            }
        }

        ~Thread() {}

    private:
        pthread_t _tid;
        std::string _name;
        bool _isrunning;
        bool _isdetach;
        void *_ret;
        fun_t _fun;
    };
}